package com.wut.clock.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wut.clock.common.exception.Asserts;
import com.wut.clock.dto.admin.MenuParams;
import com.wut.clock.entity.SysMenu;
import com.wut.clock.entity.SysRoleMenu;
import com.wut.clock.mapper.SysMenuMapper;
import com.wut.clock.mapper.SysRoleMenuMapper;
import com.wut.clock.service.IMenuService;
import com.wut.clock.vo.admin.MenuVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ZYH
 * @unit D9Lab
 * @description 菜单实现类
 * @date 2022/5/30 15:35
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MenuServiceImpl implements IMenuService {

    private final SysMenuMapper menuMapper;

    private final SysRoleMenuMapper roleMenuMapper;

    @Override
    public List<MenuVo> listMenuVosByUserId(Integer userId) {
        List<SysMenu> menuList = listMenusByUserId(userId);
        return transform2TreeMenuVo(menuList);
    }

    @Override
    public List<SysMenu> listMenusByUserId(Integer userId) {
        return menuMapper.listMenusByUserId(userId);
    }

    @Override
    public Set<String> getMenuPermsByUserId(Integer userId) {
        List<String> perms = menuMapper.selectMenuPermsByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (String perm : perms)
        {
            if (StringUtils.isNotEmpty(perm))
            {
                permsSet.addAll(Arrays.asList(perm.trim().split(",")));
            }
        }
        return permsSet;
    }

    @Override
    public List<MenuVo> listMenuVosByRoleId(Integer roleId) {
        List<SysMenu> menuList = menuMapper.listMenusByRoleId(roleId);
        return transform2TreeMenuVo(menuList);
    }

    @Override
    public int insertOneMenu(MenuParams menuParams) {
        if(menuParams.getParentId()<=100){
            // 判断url不能重复
            if(!checkPathUnique(menuParams)){
                Asserts.fail("菜单路径重复");
            }
        }
        // 判断菜单名称不能重复
        if(!checkNameUnique(menuParams)){
            Asserts.fail("菜单名称重复");
        }
        SysMenu sysMenu = new SysMenu();
        BeanUtils.copyProperties(menuParams,sysMenu);
        if(menuParams.getSort()==0||menuParams.getSort()==null){
            Integer maxSortByParentId = menuMapper.getMaxSortByParentId(menuParams.getParentId());
            if(maxSortByParentId==null){
                maxSortByParentId=0;
            }
            sysMenu.setSort(maxSortByParentId+1);
        }
        Integer maxMenuIdByParentId = menuMapper.getMaxMenuIdByParentId(menuParams.getParentId());
        if(maxMenuIdByParentId==null){
            Integer maxMenuId = menuMapper.getMaxMenuId();
            sysMenu.setId(maxMenuId-(maxMenuId%10)+20);
            if(menuParams.getParentId()==0){
                sysMenu.setId(maxMenuId+1);
            }
            return menuMapper.insert(sysMenu);
        }
        sysMenu.setId(maxMenuIdByParentId+1);
        return menuMapper.insert(sysMenu);
    }


    @Override
    public boolean checkPathUnique(MenuParams menuParams) {
        Integer menuId = menuParams.getId()==null? -1:menuParams.getId();
        SysMenu pathMenu = menuMapper.checkPathUnique(menuParams.getPath());
        log.info("路径:{}",menuParams.getPath());
        log.info("根据路径查出来的菜单:{}",pathMenu);
        if(pathMenu!=null&&pathMenu.getId().intValue()!=menuId.intValue()){
            return false;
        }
        return true;
    }

    @Override
    public boolean checkNameUnique(MenuParams menuParams) {
        Integer menuId = menuParams.getId()==null? -1:menuParams.getId();
        SysMenu nameMenu = menuMapper.checkNameUnique(menuParams.getName());
        if (nameMenu!=null&&nameMenu.getId().intValue()!= menuId.intValue()){
            return false;
        }
        return true;
    }

    @Override
    public int deleteOneMenu(Integer menuId) {
        //删除sys_role_menu中的记录
        QueryWrapper<SysRoleMenu> roleMenus = new QueryWrapper<SysRoleMenu>().eq("menu_id", menuId);
        if(roleMenus != null){
            roleMenuMapper.delete(roleMenus);
        }
        return menuMapper.deleteById(menuId);
    }


    @Override
    public int updateMenu(MenuParams menuParams) {
        // 判断url不能重复
        if(!checkPathUnique(menuParams)){
            Asserts.fail("菜单路径重复");
        }
        // 判断菜单名称不能重复
        if(!checkNameUnique(menuParams)){
            Asserts.fail("菜单名称重复");
        }
        SysMenu sysMenu = new SysMenu();
        BeanUtils.copyProperties(menuParams,sysMenu);
        return menuMapper.updateById(sysMenu);
    }

    @Override
    public List<MenuVo> listMenuVos() {
        List<SysMenu> menuList = menuMapper.selectList(new QueryWrapper<SysMenu>().eq("deleted", 0).orderByAsc("parent_id","sort"));
        return transform2TreeMenuVoTo(menuList);
    }

    /**
     * 把菜单构建成树形结构（供分配菜单时获取所有菜单使用）
     * @param sysMenus 菜单对象
     * @return 菜单VO列表
     */
    private List<MenuVo> transform2TreeMenuVoTo(List<SysMenu> sysMenus){
        List<MenuVo> menuVos = sysMenus.stream()
                .filter(sysMenu -> sysMenu.getParentId().equals(0))
                .sorted(Comparator.comparingInt(SysMenu::getSort))
                .map(sysMenu->covertTo(sysMenu,sysMenus))
                .collect(Collectors.toList());
        return menuVos;
    }

    /**
     * 把菜单构建成树形结构(供前端展示使用)
     * @param sysMenus 菜单对象
     * @return 菜单VO列表
     */
    private List<MenuVo> transform2TreeMenuVo(List<SysMenu> sysMenus){
        List<MenuVo> menuVos = sysMenus.stream()
                .filter(sysMenu -> sysMenu.getParentId().equals(0))
                .sorted(Comparator.comparingInt(SysMenu::getSort))
                .map(sysMenu->covertTo(sysMenu,sysMenus))
                .collect(Collectors.toList());
        return menuVos;
    }

    /**
     * 递归把子节点放入父节点（供分配菜单时获取所有菜单使用）
     * @param sysMenu 菜单
     * @param menuNodes 菜单节点
     * @return MenuVo
     */
    private MenuVo covertTo(SysMenu sysMenu, List<SysMenu> menuNodes){
        //转换成Vo
        MenuVo menuVo = transform2Vo(sysMenu);
        List<MenuVo> subMenuNodes=menuNodes.stream()
                .filter(subMenuNode->subMenuNode.getParentId().equals(menuVo.getId()))
                .map(subMenuNode->covertTo(subMenuNode,menuNodes))
                .collect(Collectors.toList());
        menuVo.setChildren(subMenuNodes);
        return menuVo;
    }


    /**
     * 从pojo转成Vo
     * @param sysMenu 菜单
     * @return MenuVo
     */
    private MenuVo transform2Vo(SysMenu sysMenu){
        MenuVo menuVo = new MenuVo();
        BeanUtils.copyProperties(sysMenu,menuVo);
        return menuVo;
    }
}
